package nape.phys;
import zpp_nape.Config;
import zpp_nape.Const;
import zpp_nape.util.Flags;
import DummyNapeMain;
import zpp_nape.util.Math;
import zpp_nape.util.Names;
import zpp_nape.util.Pool;
import zpp_nape.util.Lists;
import zpp_nape.shape.Circle;
import zpp_nape.shape.Edge;
import zpp_nape.space.Space;
import zpp_nape.shape.Polygon;
import zpp_nape.shape.Shape;
import zpp_nape.phys.FeatureMix;
import zpp_nape.phys.FluidProperties;
import zpp_nape.phys.Material;
import zpp_nape.phys.Body;
import zpp_nape.geom.AABB;
import zpp_nape.geom.Distance;
import zpp_nape.geom.Mat23;
import zpp_nape.geom.Vec2;
import zpp_nape.geom.VecMath;
import zpp_nape.geom.Collide;
import zpp_nape.dynamics.Arbiter;
import zpp_nape.dynamics.Contact;
import zpp_nape.dynamics.InteractionFilter;
import zpp_nape.constraint.Constraint;
import zpp_nape.dynamics.SpaceArbiterList;
import zpp_nape.constraint.Matrices;
import zpp_nape.constraint.PivotJoint;
import zpp_nape.constraint.WeldJoint;
import nape.util.Flags;
import nape.util.Lists;
import nape.util.Debug;
import nape.space.Space;
import nape.shape.Circle;
import nape.shape.Polygon;
import nape.shape.Edge;
import nape.shape.Shape;
import nape.phys.FluidProperties;
import nape.phys.Body;
import nape.geom.AABB;
import nape.geom.Geom;
import nape.geom.Mat23;
import nape.geom.Vec2;
import nape.dynamics.Contact;
import nape.dynamics.Arbiter;
import nape.dynamics.InteractionFilter;
#if swc@:keep#end class Material{
    public var zpp_inner:ZPP_Material;
    public var shared(flibget_shared,flibset_shared):Bool;
    inline function flibget_shared()return zpp_inner.shared inline function flibset_shared(shared:Bool){
        if(this.shared!=shared){
            if(this.shared&&!zpp_inner.shapes.empty()){
                while(zpp_inner.shapes.begin().next!=null){
                    var s=zpp_inner.shapes.pop_unsafe();
                    s.material=zpp_inner.copy();
                    s.material.shapes.add(s);
                }
            }
            zpp_inner.shared=shared;
        }
        return this.shared;
    }
    public var shapes(flibget_shapes,never):ShapeList;
    inline function flibget_shapes(){
        if(zpp_inner.wrap_shapes==null)zpp_inner.wrap_shapes=ZPP_ShapeList.get(zpp_inner.shapes,true);
        return zpp_inner.wrap_shapes;
    }
    public function new(?elasticity:Float=0.0,?dynamicFriction:Float=1.0,?staticFriction:Float=2.0,?density:Float=1){
        zpp_inner={
            if(ZPP_Material.zpp_pool==null)new ZPP_Material();
            else{
                var ret=ZPP_Material.zpp_pool;
                ZPP_Material.zpp_pool=ret.next;
                ret;
            }
        };
        zpp_inner.outer=this;
        this.elasticity=elasticity;
        this.dynamicFriction=dynamicFriction;
        this.staticFriction=staticFriction;
        this.density=density;
    }
    #if swc@:keep#end public inline function copy(){
        return new Material(elasticity,dynamicFriction,staticFriction,density);
    }
    public var elasticity(flibget_elasticity,flibset_elasticity):Float;
    inline function flibget_elasticity()return("elasticity"=="density"?1000:1)*zpp_inner.elasticity inline function flibset_elasticity(elasticity:Float){
        if(elasticity!=this.elasticity){
            if(({
                #if flash9 var ret:Bool=untyped __global__["isNaN"](elasticity);
                ret;
                #else Math.isNaN(elasticity);
                #end
            }))throw "Error: Material::"+"elasticity"+" cannot be NaN";
            if(elasticity<0)throw "Error: Material::"+"elasticity"+" ("+elasticity+") must be >= 0";
            if("elasticity"=="density"&&elasticity==0)throw "Error: Material::density cannot be 0";
            if("elasticity"!="elasticity"&&elasticity==ZPP_Const.POSINF)throw "Error: Material::"+"elasticity"+" cannot be infinite";
            if("elasticity"=="density")zpp_inner.elasticity=elasticity*0.001;
            else zpp_inner.elasticity=elasticity;
            zpp_inner.invalidate(ZPP_Material.WAKE|ZPP_Material.ARBITERS);
        }
        return this.elasticity;
    }
    public var dynamicFriction(flibget_dynamicFriction,flibset_dynamicFriction):Float;
    inline function flibget_dynamicFriction()return("dynamicFriction"=="density"?1000:1)*zpp_inner.dynamicFriction inline function flibset_dynamicFriction(dynamicFriction:Float){
        if(dynamicFriction!=this.dynamicFriction){
            if(({
                #if flash9 var ret:Bool=untyped __global__["isNaN"](dynamicFriction);
                ret;
                #else Math.isNaN(dynamicFriction);
                #end
            }))throw "Error: Material::"+"dynamicFriction"+" cannot be NaN";
            if(dynamicFriction<0)throw "Error: Material::"+"dynamicFriction"+" ("+dynamicFriction+") must be >= 0";
            if("dynamicFriction"=="density"&&dynamicFriction==0)throw "Error: Material::density cannot be 0";
            if("dynamicFriction"!="elasticity"&&dynamicFriction==ZPP_Const.POSINF)throw "Error: Material::"+"dynamicFriction"+" cannot be infinite";
            if("dynamicFriction"=="density")zpp_inner.dynamicFriction=dynamicFriction*0.001;
            else zpp_inner.dynamicFriction=dynamicFriction;
            zpp_inner.invalidate(ZPP_Material.WAKE|ZPP_Material.ANGDRAG|ZPP_Material.ARBITERS);
        }
        return this.dynamicFriction;
    }
    public var staticFriction(flibget_staticFriction,flibset_staticFriction):Float;
    inline function flibget_staticFriction()return("staticFriction"=="density"?1000:1)*zpp_inner.staticFriction inline function flibset_staticFriction(staticFriction:Float){
        if(staticFriction!=this.staticFriction){
            if(({
                #if flash9 var ret:Bool=untyped __global__["isNaN"](staticFriction);
                ret;
                #else Math.isNaN(staticFriction);
                #end
            }))throw "Error: Material::"+"staticFriction"+" cannot be NaN";
            if(staticFriction<0)throw "Error: Material::"+"staticFriction"+" ("+staticFriction+") must be >= 0";
            if("staticFriction"=="density"&&staticFriction==0)throw "Error: Material::density cannot be 0";
            if("staticFriction"!="elasticity"&&staticFriction==ZPP_Const.POSINF)throw "Error: Material::"+"staticFriction"+" cannot be infinite";
            if("staticFriction"=="density")zpp_inner.staticFriction=staticFriction*0.001;
            else zpp_inner.staticFriction=staticFriction;
            zpp_inner.invalidate(ZPP_Material.WAKE|ZPP_Material.ARBITERS);
        }
        return this.staticFriction;
    }
    public var density(flibget_density,flibset_density):Float;
    inline function flibget_density()return("density"=="density"?1000:1)*zpp_inner.density inline function flibset_density(density:Float){
        if(density!=this.density){
            if(({
                #if flash9 var ret:Bool=untyped __global__["isNaN"](density);
                ret;
                #else Math.isNaN(density);
                #end
            }))throw "Error: Material::"+"density"+" cannot be NaN";
            if(density<0)throw "Error: Material::"+"density"+" ("+density+") must be >= 0";
            if("density"=="density"&&density==0)throw "Error: Material::density cannot be 0";
            if("density"!="elasticity"&&density==ZPP_Const.POSINF)throw "Error: Material::"+"density"+" cannot be infinite";
            if("density"=="density")zpp_inner.density=density*0.001;
            else zpp_inner.density=density;
            zpp_inner.invalidate(ZPP_Material.WAKE|ZPP_Material.PROPS);
        }
        return this.density;
    }
    @:keep public inline function toString(){
        return "{ elasticity: "+elasticity+" dynamicFriction: "+dynamicFriction+" staticFriction: "+staticFriction+" density: "+density+" }";
    }
    #if swc@:keep#end public inline function Wood()return new Material(0.4,0.2,0.38,0.7)#if swc@:keep#end public inline function Steel()return new Material(0.2,0.57,0.74,7.8)#if swc@:keep#end public inline function Ice()return new Material(0.3,0.03,0.1,0.9)#if swc@:keep#end public inline function Rubber()return new Material(0.8,1.0,1.4,1.5)#if swc@:keep#end public inline function Glass()return new Material(0.4,0.4,0.94,2.6)
}
